﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Dycox.Collections;

namespace Dycox.Workflows
{

    public class TransitionCollection : OwnedCollection<Transition, Workflow>
    {
        public TransitionCollection(Workflow workflow)
            : base(workflow)
        {

        }

        protected override void SetItemOwner(Transition item, Workflow parent)
        {
            if (item != null)
            {
                if (item.Workflow != parent)
                    throw new InvalidOperationException("Item is not belong to this workflow.");

                if (this[item.SourceStage, item.TargetStage] != null)
                    throw new InvalidOperationException("A transition has same source and target is already existed.");
            }
        }

        protected override Workflow GetItemOwner(Transition item)
        {
            return item.Workflow;
        }

        internal IEnumerable<Transition> GetTransitionsInternal(Stage source, Stage target, TransitionTypes types)
        {
            if (source == null && target == null || types == TransitionTypes.None)
                return null;

            IEnumerable<Transition> q = this;
            if (source != null)
                q = q.Where(o => o.SourceStage == source);
            if (target != null)
                q = q.Where(o => o.TargetStage == target);

            if (types != TransitionTypes.All)
            {
                q = q.Where(o => (o.Type & types) == o.Type);
            }

            return q;
        }

        public Transition[] GetOutgoingTransitions(Stage source)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            return this.GetTransitionsInternal(source, null, TransitionTypes.All).ToArray();
        }

        public Stage[] GetOutgoingStages(Stage source)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            return this.GetTransitionsInternal(source, null, TransitionTypes.Normal)
                .Select(o => o.TargetStage).ToArray();
        }

        public Transition[] GetIncomingTransitions(Stage target)
        {
            if (target == null)
                throw new ArgumentNullException("target");
            return this.GetTransitionsInternal(null, target, TransitionTypes.All).ToArray();
        }

        public Stage[] GetIncomingStages(Stage target)
        {
            if (target == null)
                throw new ArgumentNullException("target");
            return this.GetTransitionsInternal(null, target, TransitionTypes.Normal).Select(o => o.SourceStage).ToArray();
        }

        public Transition GetTransition(Stage stage, TransitionTypes type)
        {
            switch (type)
            {
                case TransitionTypes.NoMoreStep:
                    return this[stage, Owner.NoMoreStep];
                case TransitionTypes.ExitStage:
                    return this[stage, Owner.AnyStage];
                default:
                    throw new ArgumentException("Transition type is not valid.", "type");
            }
        }

        public Transition this[Stage source, Stage target]
        {
            get
            {
                if (source == null || target == null)
                    throw new ArgumentNullException();

                var array = this.GetTransitionsInternal(source, target, TransitionTypes.All).ToArray();
                System.Diagnostics.Debug.Assert(array.Length <= 1, "Why the transition collection contains more than one similar elements.");
                if (array.Length == 0) return null;
                else return array[0];
            }
        }
    }

    internal enum PlaceHolderFlag
    {
        DontCare,
        NoPlaceHolder,
        OnlyPlaceHolder
    }

    //public class TransitionCollection : OwnedCollection<Transition, Stage>
    //{
        //public TransitionCollection(Stage stage)
        //    : base(stage)
        //{

        //}

        //protected override void SetItemOwner(Transition item, Stage stage)
        //{
        //    item.SourceStage = stage;
        //}

        //protected override Stage GetItemOwner(Transition item)
        //{
        //    return item.SourceStage;
        //}
    //}

}
